/*
@file: libManager.cpp
@author: ZZH
@date: 2022-09-29
@info: 外部库管理器
*/
#include "libManager.h"
#include "symTable.h"
#include "InnerLib.h"

QMap<QString, LibManager_t::LibOps> LibManager_t::libMap;
bool LibManager_t::isInnerFuncLoaded = false;

bool LibManager_t::LoadLib(const QString& path, const QString& libName)
{
    LibManager_t::loadBasicLibs();
#if defined(DEBUG) || defined(__DEBUG)
    LibManager_t::importInnerFunc();
#endif

    COMP_INFO("load lib: %s", libName.toStdString().c_str());
    QLibrary lib(QString("%1/%2").arg(path).arg(libName.split('.')[0]));
    if (!lib.load())
    {
        COMP_INFO("lib %s load error: %s", libName.toStdString().c_str(), lib.errorString().toStdString().c_str());
        return false;
    }

    COMP_INFO("load lib succ");
    auto pfInit = reinterpret_cast<LibManager_t::LinInitFun_t>(lib.resolve("lib_init"));//解析lib_init函数, 作为库入口点
    if (nullptr != pfInit)
    {
        COMP_INFO("calling init");
        auto libFuncs = pfInit();
        while (nullptr != libFuncs->sym)//不为空则导入下一个
        {
            const char* finalName = nullptr == libFuncs->name ? libFuncs->sym : libFuncs->name;
            auto pf = lib.resolve(libFuncs->sym);
            if (nullptr != pf)
            {
                COMP_INFO("load fun: %s", finalName);
                FunSymTable.insert(finalName, {
                    reinterpret_cast<ASTFunctionCall_t::pf>(pf), libFuncs->argNum
                });
            }
            else
            {
                COMP_INFO("load %s function error", finalName);
            }
            libFuncs++;
        }

        auto pfExit = lib.resolve("lib_exit");
        libMap.insert(libName, { pfInit, pfExit });
    }

    return true;
}

void LibManager_t::importInnerFunc(void)
{
    if (LibManager_t::isInnerFuncLoaded)
        return;
    LibManager_t::isInnerFuncLoaded = true;

    FunSymTable.insert("__fs", { fs, 1 });
}

void LibManager_t::loadBasicLibs(void)
{
    const char* libs[] = {
        "fft", "libCommon"
    };

#if ANDROID
    QString libPath = "../lib/lib%1.so";
#else
    QString libPath = "./lib/lib%1.dll";
#endif

    for (auto libn : libs)
    {
        QLibrary lib(libPath.arg(libn));
        if (false == lib.load())
            COMP_INFO("basic lib %s load fail", libn);
    }
}
